#include "ModelEditDlg.h"
#include "QGView.h"
#include <QPushButton>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QGraphicsRectItem>
#include <QPlainTextEdit>
#include <QDebug>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QFileInfo>
#include <QMessageBox>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <random>
#include "QGScene.h"
#include "BaseItem.h"
#include "CustomRectItem.h"

#include "Visionapi.h"
#include "ICamera.h"
#include "VisionMainWnd.h"
#include "InspectLL.h"

extern FrameControl frame_grab_ctrl;

ModelEditDlg::ModelEditDlg(QWidget* parent)
{
	setParent(parent, windowFlags());

	initLayout();

	setWindowTitle("模板编辑");
	setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);

	setMinScore(0.6);
	//QImage imgTest;
	//imgView_->DispImage(imgTest);
}

ModelEditDlg::~ModelEditDlg()
{

}

void ModelEditDlg::initLayout()
{
	// 1.主控件，用以承载所有布局
	QWidget* mainWidget = new QWidget(this);

	// 2.左侧图像显示区域
	QWidget* leftViewWidget = new QWidget(mainWidget);
	//leftViewWidget->setMinimumSize(640, 480);
	imgView_ = new QGView(mainWidget);
	imgView_->setObjectName("imgView");
	// 将view放到layout中管理，图像能够实现自适应显示
	QVBoxLayout* leftLyt = new QVBoxLayout(leftViewWidget);
	leftLyt->addWidget(imgView_);

	// 3.右侧图像模板编辑控件区域
	QWidget* rightPaneWidget = new QWidget(mainWidget);
	initRightWidget(rightPaneWidget);

	// 4.主布局
	QHBoxLayout* mainLayout = new QHBoxLayout(mainWidget);
	mainLayout->addWidget(leftViewWidget);
	mainLayout->addWidget(rightPaneWidget);

	setLayout(mainLayout);
}

void ModelEditDlg::initRightWidget(QWidget* rightPaneWidget)
{
	rightPaneWidget->setFixedWidth(300);

	QLabel* modelName = new QLabel("料号名称:", rightPaneWidget);
	QLineEdit* editName = new QLineEdit(rightPaneWidget);
	editName->setObjectName("partName");
	QHBoxLayout* modelLyt = new QHBoxLayout();
	modelLyt->addWidget(modelName);
	modelLyt->addWidget(editName);
	QPushButton* loadModel = new QPushButton("加载模板", rightPaneWidget);
	QPushButton* snapOneImg = new QPushButton("采集图像", rightPaneWidget);
	QPushButton* save = new QPushButton("模板保存", rightPaneWidget);
	QPushButton* addRoi = new QPushButton("添加模板ROI", rightPaneWidget);
	QPushButton* btnSetRoi = new QPushButton("设置搜索ROI", rightPaneWidget);

	QPushButton* delRoi = new QPushButton("删除ROI", rightPaneWidget);
	QPushButton* setSearchRoi = new QPushButton("设置ROI", rightPaneWidget);
	QPushButton* analyze = new QPushButton("模板分析", rightPaneWidget);
	QPushButton* test = new QPushButton("测试", rightPaneWidget);
	QTableWidget* shapeMatchResults = new QTableWidget(rightPaneWidget);
	shapeMatchResults->setObjectName("ShapeMatchTable");
	initTableWidget(shapeMatchResults);

	QVBoxLayout* rightLyt = new QVBoxLayout(rightPaneWidget);
	rightLyt->addLayout(modelLyt);
	rightLyt->addWidget(snapOneImg);
	rightLyt->addWidget(loadModel);
	rightLyt->addWidget(addRoi);
	rightLyt->addWidget(btnSetRoi);
	rightLyt->addWidget(delRoi);
	rightLyt->addWidget(setSearchRoi);
	rightLyt->addWidget(analyze);
	rightLyt->addWidget(save);
	rightLyt->addWidget(test);
	rightLyt->addWidget(shapeMatchResults);

	rightLyt->addStretch();
	connect(loadModel, &QPushButton::clicked, this, &ModelEditDlg::on_load_model);
	connect(addRoi, &QPushButton::clicked, this, &ModelEditDlg::on_add_roi);
	connect(delRoi, &QPushButton::clicked, this, &ModelEditDlg::on_del_roi);
	connect(btnSetRoi, &QPushButton::clicked, this, &ModelEditDlg::on_Set_SearchRoi);
	connect(save, &QPushButton::clicked, this, &ModelEditDlg::on_save_model);
	connect(analyze, &QPushButton::clicked, this, &ModelEditDlg::on_analyze);
	connect(test, &QPushButton::clicked, this, &ModelEditDlg::on_test);
	connect(snapOneImg, &QPushButton::clicked, this, &ModelEditDlg::on_snap_image);
	connect(setSearchRoi, &QPushButton::clicked, this, &ModelEditDlg::on_set_roi);
}

void ModelEditDlg::initTableWidget(QTableWidget* tab)
{
	tab->setEditTriggers(QAbstractItemView::NoEditTriggers);
	tab->setColumnCount(6);
	tab->setSelectionBehavior(QAbstractItemView::SelectRows);
	tab->setSelectionMode(QAbstractItemView::SingleSelection);

	QFont headerFont = tab->horizontalHeader()->font();
	headerFont.setBold(true);
	tab->horizontalHeader()->setFont(headerFont);

	//设置显示内容
	QStringList headerTitle;
	headerTitle << "ID" << "分数" << "行" << "列" << "角度" << "缩放";
	tab->setHorizontalHeaderLabels(headerTitle);
	int colsWidth[] = {15,35,50,50,50,35};
	for (int i = 0; i < 6; i++)
	{
		tab->setColumnWidth(i, colsWidth[i]);
	}
}


void ModelEditDlg::addResuts(HTuple modelIds, HTuple rows, HTuple cols, HTuple scales, HTuple angles, HTuple scores)
{
	//headerTitle << "模板ID" << "分数" << "行" << "列" << "角度" << "缩放";
	QTableWidget* tab = findChild<QTableWidget*>("ShapeMatchTable");
	int count = modelIds.Length();
	QString str;
	for (int i = 0; i < count; i++)
	{
		int row = tab->rowCount();
		tab->insertRow(row);

		QTableWidgetItem* item = new QTableWidgetItem;
		item->setText(QString::number(modelIds[i].I()));
		tab->setItem(row, 0, item);
		
		double infos[] = { scores[i].D() ,rows[i].D() ,cols[i].D(), VisionApi::rad2Deg(angles[i].D()),scales[i].D() };
		for (int j = 0; j < 5; j++)
		{
			auto txt = QString::number(infos[j], 'f', 2);
			item = new QTableWidgetItem;
			item->setText(txt);
			tab->setItem(row, j+1, item);
		}
	}
}

void ModelEditDlg::on_add_roi()
{
	auto item = new RectangleItem(100, 100, 200, 200);
	item->setItemName("model_1");
	imgView_->AddItems(item);
}

void ModelEditDlg::on_del_roi()
{
	auto scene = imgView_->scene;
	// 获取当前选中的所有项
	QList<QGraphicsItem*> selectedItems = scene->selectedItems();

	// 遍历并删除选中的项
	foreach(QGraphicsItem * item, selectedItems) {
		scene->removeItem(item);
		delete item; // 如果你的项是通过new创建的，需要显式调用delete
	}
}

void ModelEditDlg::on_snap_image()
{
	VisionMainWnd* parentWnd = (VisionMainWnd*)parentWidget();
	// 获取相机实例
	auto cam = parentWnd->getCamera();
	if (!cam->IsConnected())
	{
		QString imgPath = QFileDialog::getOpenFileName(this, "模板图像", "", "Image Format(*.png *.jpg *.bmp All(*.*))");
		if (imgPath.isEmpty())
		{
			qInfo() << "没有图像选中";
			return;
		}

		imgLoad_.load(imgPath);
	}
	else
	{
		// 暂停采集循环线程
		parentWnd->pauseGrab(true);

		// 触发：采集一帧
		cam->ExecuteSoftwareTrigger();

		cv::Mat img;
		int ret = cam->getImageBuffer(img, 200);
		if (ret)
		{
			qInfo() << "采集失败";
			parentWnd->pauseGrab(false);
			return;
		}
		imgLoad_ = VisionApi::mat2QImage(img);
	}

	imgView_->DispImage(imgLoad_);

	parentWnd->pauseGrab(false);
}

void ModelEditDlg::on_Set_SearchRoi()
{
	auto item = new RectangleItem(100, 100, 200, 200);
	item->setObjectName("roi");
	imgView_->AddItems(item);
}



void ModelEditDlg::on_load_model()
{
	QStringList modelFiles = QFileDialog::getOpenFileNames(nullptr, "加载模板", "model", "*.shm");
	if (modelFiles.isEmpty())
	{
		qInfo() << "请选择模板...";
		return;
	}

	HTuple modelIds;
	for (auto& m : modelFiles)
	{
		QFileInfo fileInfo(m);
		QString modelName = fileInfo.fileName();
		HTuple model;
		HalconCpp::ReadShapeModel(m.toStdString().c_str(), &model);
		modelIds.Append(model);
	}
	mulShapeModel_.SetFromTuple(modelIds);
}

void ModelEditDlg::on_save_model()
{
	int modelCount = mulShapeModel_.Length();
	if (modelCount < 1)
	{
		QMessageBox::warning(nullptr, "保存模板", "模板为空，请检查", QMessageBox::Abort);
		return;
	}

	QLineEdit* pn = findChild<QLineEdit*>("partName");
	if (pn->text().isEmpty())
	{
		QMessageBox::information(nullptr, "保存模板", "请输出料号名称.", QMessageBox::Abort);
		return;
	}


	QString modelFileName = QFileDialog::getSaveFileName(nullptr, "保存模板", pn->text().toStdString().c_str());
	//for (int i = 0; i < modelCount; i++)
	{
		//QString shapeModelPath = modelFileName + "_" + QString::number(i) + ".shm";
		QString shapeModelPath = modelFileName + ".shm";
		HalconCpp::WriteShapeModel(mulShapeModel_.ConvertToTuple()[0], shapeModelPath.toStdString().c_str());
	}

	// 保存ROI

}

void ModelEditDlg::on_analyze()
{
	createShapeModel();

	//createShapeModel_xld();
	 
	 
	cv::Mat src = VisionApi::qImage2Mat(imgLoad_);
	findObject(src);
}


void ModelEditDlg::on_set_roi()
{
	RectangleItem* item = (RectangleItem*)getRoiRectItem("roi");
	if (item == nullptr)
	{
		QMessageBox::information(nullptr, "ROI设置", "请设置搜索roi", QMessageBox::Ok);
		return;
	}
	auto rect = item->getQRectF();
	// 将roi写配置文件
	cv::Rect roi(int(rect.x()), int(rect.y()), int(rect.width()), int(rect.height()));

	auto p = (VisionMainWnd*)parentWidget();
	p->getInspect()->setRoiRect(roi);
	p->getRoiRectItem()->SetObject(item->getRect());

	searchRoi_.GenRectangle1(roi.y, roi.x, roi.y + roi.height, roi.x + roi.width);
	QVector<QVector<int>> rectPoints = {
		{roi.x, roi.y},
		{roi.x+roi.width, roi.y+roi.height}
	};
	// 创建根数组
	QJsonArray rootArray;

	// 填充坐标数据
	for (const auto& point : rectPoints) {
		QJsonArray pointArray;
		pointArray.append(point[0]);
		pointArray.append(point[1]);
		rootArray.append(pointArray);
	}

	QJsonDocument readAlg;
	QString modelFilePath = QApplication::applicationDirPath() + "/model/model.json";
	QFile file(modelFilePath);
	if (!file.exists())
	{
		qInfo() << "modbus settings file isn't exist.";
		return;
	}

	QByteArray jsonData;
	if (file.open(QIODevice::ReadOnly)) {
		jsonData = file.readAll();
		file.close();
	}

	QJsonParseError error;
	QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &error);
	if (error.error == QJsonParseError::NoError)
	{
		if (jsonDoc.isObject())
		{
			auto obj = jsonDoc.object();
			obj["search_roi"] = rootArray;		
			jsonDoc.setObject(obj);
		}
	}
	else
	{
		qWarning() << "读取模板文件失败.";
	}

	QFile fileSave(modelFilePath);
	if (fileSave.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
		fileSave.write(jsonDoc.toJson());
		fileSave.close();
	}
}

void ModelEditDlg::on_test()
{
	cv::Mat src = VisionApi::qImage2Mat(imgLoad_);
	findObject(src);
}

void ModelEditDlg::drawResult(QImage& src, HXLDCont& xld)
{
	QPainter paint(&src);
	QPen drawPen(Qt::red, 1);
	paint.setPen(drawPen);
	int objCount = xld.CountObj();

	for (int i = 0; i < objCount; i++)
	{
		auto obj = xld.SelectObj(i + 1);

		QPolygon ply;
		HTuple rows, cols;
		obj.GetContourXld(&rows, &cols);
		int len = rows.Length();
		for (int j = 0; j < len; j++)
		{
			ply << QPoint(cols[j].D(), rows[j].D());
		}

		paint.drawPolygon(ply);

	}
}

void ModelEditDlg::drawResult(cv::Mat& src, HXLDCont& xld)
{
	using cvContour = std::vector<cv::Point>;

	int objCount = xld.CountObj();
	for (int i = 0; i < objCount; i++)
	{
		auto obj = xld.SelectObj(i + 1);

		cvContour c;
		HTuple rows, cols;
		obj.GetContourXld(&rows, &cols);
		int len = rows.Length();
		for (int j = 0; j < len; j++)
		{
			c.push_back(cv::Point(cols[j].D(), rows[j].D()));
		}

		std::random_device rd;
		std::mt19937 gen(rd());
		std::uniform_int_distribution<int> dis(100, 255);
		auto color = cv::Scalar(dis(gen),
			dis(gen),
			dis(gen));
		cv::polylines(src, c, false, color, 2, cv::LINE_AA, 0);
	}
}

rectArray ModelEditDlg::getRectArrayFromViews()
{
	rectArray rtArrys;

	auto items = imgView_->items();
	int count = items.size() / 6;
	for (int i = 0; i < count; i++)
	{
		RectangleItem* item = (RectangleItem*)items.at(i * 6 + 5);
		auto rect = item->getRect();
		rtArrys.push_back(cv::Rect(rect.X, rect.Y, rect.Width, rect.Height));
	}

	return rtArrys;
}

bool ModelEditDlg::createShapeModel()
{
	auto items = imgView_->items();
	int count = items.size() / 6;
	if (count == 0)
	{
		qInfo() << "请设置ROI区域";
		return false;
	}
	HImage modelImg;
	bool suc = VisionApi::QImage2HImage(imgLoad_, modelImg);
	modelImg = modelImg.MedianImage("square", 1.0, "mirrored");

	HXLDCont modelContour;
	std::vector<HShapeModel> shapeModels;
	allModelContours_.clear();
	for (int i = 0; i < count; i++)
	{

		RectangleItem* item = (RectangleItem*)items.at(i * 6 + 5);
		auto rect = item->getRect();

		HRegion roi;
		roi.GenRectangle1(rect.Y, rect.X, rect.Y + rect.Height, rect.X + rect.Width);

		auto reduce1 = modelImg.ReduceDomain(roi);

		HShapeModel sh1 = reduce1.CreateScaledShapeModel(HTuple("auto"), HTuple(1).TupleRad(), HTuple(360).TupleRad(), HTuple("auto"),
			HTuple(0.8), HTuple(1.2), HTuple("auto"), HTuple("auto"), HTuple("use_polarity"), HTuple("auto"), HTuple("auto"));
		shapeModels.push_back(sh1);

		modelContour = sh1.GetShapeModelContours(1);
		allModelContours_.push_back(modelContour);
	}

	int modelCount = shapeModels.size();
	auto p = new HShapeModel[modelCount];
	for (int i = 0; i < modelCount; i++)
	{
		p[i] = shapeModels[i];
	}
	mulShapeModel_.Clear();
	// 建立多模板
	mulShapeModel_ = HShapeModelArray(p, modelCount);

	return true;
}

bool ModelEditDlg::createShapeModel_xld()
{
	auto allRois = getRectArrayFromViews();
	if (allRois.size() == 0)
	{
		return false;
	}

	HImage modelImg;
	bool suc = VisionApi::QImage2HImage(imgLoad_, modelImg);
	// 滤波，避免杂点干扰
	modelImg = modelImg.MedianImage("square", 1.5, "mirrored");

	HRegion darkObjs = modelImg.VarThreshold(55, 55, 0.2, 25, "dark");
	auto closeReg = darkObjs.ClosingCircle(1.5);
	auto openReg = closeReg.OpeningCircle(1.5);

	HXLDCont modelContour;
	std::vector<HShapeModel> shapeModels;
	allModelContours_.clear();
	for (auto& r : allRois)
	{
		HRegion roi;
		roi.GenRectangle1(r.y, r.x, r.y + r.height, r.x+r.width);
		
		auto objRoi = roi.Intersection(openReg);
		auto connections = objRoi.Connection();
		auto selObj = connections.SelectShapeStd("max_area", 70.0);

		
		if (selObj.CountObj() > 0)
		{
			auto objContour = selObj.GenContourRegionXld("border");

			HShapeModel shModel;
			shModel.CreateScaledShapeModelXld(objContour, "auto", HTuple(0).TupleRad(), HTuple(360).TupleRad(), 
				"auto", 0.8, 1.2, 
				"auto", "auto", "ignore_local_polarity", 5);
				
			shapeModels.push_back(shModel);

			modelContour = shModel.GetShapeModelContours(1);
			allModelContours_.push_back(modelContour);
		}		
	}

	// 创建多模板
	int modelCount = shapeModels.size();
	auto p = new HShapeModel[modelCount];
	for (int i = 0; i < modelCount; i++)
	{
		p[i] = shapeModels[i];
	}
	// test
	HTuple modelIds;
	HTuple r, c, a, s, score;

	mulShapeModel_.Clear();
	// 建立多模板
	mulShapeModel_ = HShapeModelArray(p, modelCount);	

	return true;
}

bool ModelEditDlg::findObject(cv::Mat& src)
{
	HImage modelImg = VisionApi::HImageFromMat(src);

	// 验证模板
	HTuple modelIds;
	HTuple r, c, a, s, score;
	minScoreMatch_ = 0.5;
	modelImg.FindScaledShapeModels(mulShapeModel_, HTuple(1).TupleRad(), HTuple(360).TupleRad().D(),
		0.8, 1.2, minScoreMatch_, 0, 0.5, HTuple("least_squares").S(),
		0, 0.7, &r, &c, &a, &s, &score, &modelIds);


	auto tab = findChild<QTableWidget*>("ShapeMatchTable");
	tab->clearContents();
	tab->setRowCount(0);
	if (score.Length() > 0)
	{
		addResuts(modelIds, r, c, s, a, score);
		qInfo() << "create shape models success.";
	}

	//cv::Mat destImg = VisionApi::qImage2Mat(imgLoad_);
	cv::Mat destImg = src.clone();
	cv::cvtColor(destImg, destImg, cv::COLOR_GRAY2BGR);
	int idCount = modelIds.Length();
	for (int i = 0; i < idCount; i++)
	{
		int id = modelIds[i];
		HXLDCont transXld;
		HHomMat2D homMat;
		homMat.HomMat2dIdentity();
		homMat = homMat.HomMat2dTranslate(r[i].D(), c[i].D());
		homMat = homMat.HomMat2dRotate(a[i].D(), r[i].D(), c[i].D());
		homMat = homMat.HomMat2dScale(s[i].D(), s[i].D(), r[i].D(), c[i].D());

		auto modelCountour = mulShapeModel_.Tools()[id].GetShapeModelContours(1);
		HalconCpp::AffineTransContourXld(/*allModelContours_[id]*/modelCountour, &transXld, homMat);

		drawResult(destImg, transXld);
	}

	// 图形化显示结果
	QImage disp = VisionApi::mat2QImage(destImg);
	imgView_->DispImage(disp, true);
	imgView_->viewport()->update();

	return true;
}

QRectF ModelEditDlg::getRoiRect(QString objName)
{
	QRectF roi;

	auto items = imgView_->items();
	int count = items.size() / 6;
	if (count == 0)
	{
		return roi;
	}
	for (int i = 0; i < count; i++)
	{
		RectangleItem* it = (RectangleItem*)items.at(i * 6 + 5);
		if (it->objectName() == objName)
		{
			roi = it->getQRectF();
			break;
		}
	}
	return roi;
}

RectangleItem* ModelEditDlg::getRoiRectItem(QString objName)
{
	RectangleItem* item = nullptr;
	auto items = imgView_->items();
	int count = items.size() / 6;	
	for (int i = 0; i < count; i++)
	{
		RectangleItem* it = (RectangleItem*)items.at(i * 6 + 5);
		auto name = it->objectName();
		if (name == objName)
		{
			item = it;
			break;
		}
	}
	return item;
}


